/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dgbgui.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;

import org.flexdock.docking.DockingManager;
import org.flexdock.docking.DockingPort;
import org.flexdock.docking.defaults.DefaultDockingPort;

import dgbgui.DGBGUI;
import dgbgui.actions.ActionFactory;
import dgbgui.actions.ActionRepository;
import dgbgui.command.CommandStack;
import dgbgui.modeldocument.ModelDocument;
import dgbgui.modeldocument.ModelDrivenManager;
import dgbgui.tools.SaveTool;
import dgbgui.tools.Tool;
import edu.umd.cs.piccolox.swing.PScrollPane;

/**
 * @author bjnortier
 * MainFrame is the main application frame
 */
public class MainFrame extends JFrame implements WindowListener {

    public enum Perspective {
        DEFAULT,
        MODELDRIVEN
    }
    
	/**
	 * serialVersionUID is required for the Serializable interface
	 * This ID has been auto-generated by eclipse.
	 */
	private static final long serialVersionUID = 0L;
	
	public MainFrame() {
		super();
        
        setFilenameTitle(null);
        
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        
		// Add the menu bar
		setJMenuBar(ActionFactory.createMenuBar());
        
        m_defaultCanvasView = new DefaultCanvasView(DefaultCanvasScene.getInstance());
        m_modelDrivenOutlineView = new ModelDrivenOutlineView(ModelDrivenOutlineScene.getInstance());
        m_selectionInspector = new DefaultSelectionInspector();
        m_errorInspector = new ErrorInspector();
        m_modelDrivenInspector = new ModelDrivenInspector();
        m_modelDrivenResultsInspector = new ModelDrivenResultsInspector();
        m_statusBar = new JLabel();
        setPerspective(m_perspective);
        
        // To observe closing
        addWindowListener(this);


	}
    
    public void setPerspective(Perspective p) {
        switch (p) {
        case DEFAULT: setDefaultPerspective(); break;
        case MODELDRIVEN: setModelPerspective(); break;
        }
        // Redo the layout
        validate();
    }
    
    public Perspective getPerspective() {
        return m_perspective;
    }
    
    private void setDefaultPerspective() {
        getContentPane().removeAll();
                
        // The tool bar
        JToolBar toolBar = ActionFactory.createToolBar(ActionRepository.getInstance().getDefaultToolbarGroups());
        toolBar.setFloatable(false);
        getContentPane().add(toolBar,BorderLayout.NORTH);
        
        // The graphics view
        PScrollPane viewPanel = new PScrollPane(m_defaultCanvasView);
        
        // The inspector and error window will go into the bottom docking port
        DefaultDockingPort bottomPort = createDockingPort();
        
        // The inspector window
        JScrollPane selectionInspectorPane = new JScrollPane(m_selectionInspector.getComponent());
        DockingManager.registerDockable(selectionInspectorPane, "Inspector");
        DockingManager.dock(selectionInspectorPane ,(DockingPort)bottomPort);

        // Error panel
        JScrollPane exceptionInspectorPane = new JScrollPane(m_errorInspector.getComponent());
        DockingManager.registerDockable(exceptionInspectorPane, "Errors");
        DockingManager.dock(exceptionInspectorPane ,(DockingPort)bottomPort);
        
        // The inspector is shown by default
        // TODO: Figure out how to show the inspector by default
  
        // The main window contains the graphics panel and the docking port
        // with a splitter in between
        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,viewPanel,bottomPort);
        splitPane.setOneTouchExpandable(true);
        viewPanel.setPreferredSize(new Dimension(800,600));
        
        // Add the split pane as the main component
        getContentPane().add(splitPane);
        
        Panel statusPanel = new Panel();
        statusPanel.setLayout(new BorderLayout());
        statusPanel.add(m_statusBar,BorderLayout.CENTER);
        getContentPane().add(statusPanel,BorderLayout.SOUTH);
        
        m_statusBar.setText("LMB + Click: Select, LMB + Drag: Rectangle Select, RMB + drag: PAN, Shift + RMB + drag(up/down): ZOOM, Mouse scroll = ZOOM");
    }
    
    private void setModelPerspective() {
        getContentPane().removeAll();
        
        // ---------- Outline ----------
        
        getContentPane().setLayout(new BorderLayout());
        // The tool bar
        JToolBar toolBar = ActionFactory.createToolBar(ActionRepository.getInstance().getModelDrivenToolbarGroups());
        toolBar.setFloatable(false);
        getContentPane().add(toolBar,BorderLayout.NORTH);
        
        JPanel outline = new JPanel();
        outline.setLayout(new BoxLayout(outline,BoxLayout.Y_AXIS));
        //outline.setPreferredSize(new Dimension(300,400));
        
        JPanel selectModelPanel = new JPanel();
        selectModelPanel.setLayout(new BoxLayout(selectModelPanel,BoxLayout.X_AXIS));
        
        JComboBox modelCombo = new JComboBox(ModelDocument.getInstance().getDGBModelComboModel());
        selectModelPanel.add(modelCombo);

        JButton updateModelsButton = new JButton("Update models");
        updateModelsButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
        selectModelPanel.add(updateModelsButton);
        
        // The model driven manager observes the combo to change the 
        // current model
        modelCombo.addActionListener(ModelDrivenManager.getInstance());
        updateModelsButton.addActionListener(ModelDrivenManager.getInstance());
        
        outline.add(selectModelPanel);
        
        PScrollPane outlineScrollPane = new PScrollPane(m_modelDrivenOutlineView);
        outlineScrollPane.setPreferredSize(new Dimension(300,Short.MAX_VALUE));
        outline.add(outlineScrollPane);
        
        
        // ---------- Docking port and split pane ----------
        
        
        DefaultDockingPort bottomPort = createDockingPort();
        
        // The inspector window
        JScrollPane modelDrivenInspectorPane = new JScrollPane(m_modelDrivenInspector.getComponent());
        DockingManager.registerDockable(modelDrivenInspectorPane, "Inspector");
        DockingManager.dock(modelDrivenInspectorPane ,(DockingPort)bottomPort);
        
        // Error panel
        JScrollPane exceptionInspectorPane = new JScrollPane(m_errorInspector.getComponent());
        DockingManager.registerDockable(exceptionInspectorPane, "Errors");
        DockingManager.dock(exceptionInspectorPane ,(DockingPort)bottomPort);
        
        // Results panel
        JScrollPane resultsInspectorPane = new JScrollPane(m_modelDrivenResultsInspector.getComponent());
        DockingManager.registerDockable(resultsInspectorPane, "Results");
        DockingManager.dock(resultsInspectorPane ,(DockingPort)bottomPort);
        
        
        
        JSplitPane mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,outline,bottomPort);
        mainSplit.setOneTouchExpandable(true);
        outline.setPreferredSize(new Dimension(800,600));
        getContentPane().add(mainSplit, BorderLayout.CENTER);
        
        
        // ---------- Status ----------
        
        Panel statusPanel = new Panel();
        statusPanel.setLayout(new BorderLayout());
        statusPanel.add(m_statusBar,BorderLayout.CENTER);
        getContentPane().add(statusPanel,BorderLayout.SOUTH);
        
        m_statusBar.setText("Choose your model from the list.");
    }
    
    public void setFilenameTitle(String fileName) {
        String title = "d g b | g u i";
        if ( fileName != null ) {
            title += " - " + fileName;
        }
        setTitle(title);
    }

    
    private static DefaultDockingPort createDockingPort() {
        DefaultDockingPort port = new DefaultDockingPort();
        return port;
    }
    
    public DefaultCanvasView getDefaultCanvasView() {
        return m_defaultCanvasView;
    }
    
    public ModelDrivenOutlineView getModelDrivenOutlineView() {
        return m_modelDrivenOutlineView;
    }
    
    public DefaultSelectionInspector getSelectionInspector() {
        return m_selectionInspector;
    }
    
    public ErrorInspector getErrorInspector() {
        return m_errorInspector;
    }
    
    public ModelDrivenInspector getModelDrivenInspector() {
        return m_modelDrivenInspector;
    }
    
    public ModelDrivenResultsInspector getModelDrivenResultsInspector() {
        return m_modelDrivenResultsInspector;
    }
	

    
    // ----- Windowlistener methods -----
	

    public void windowActivated(WindowEvent arg0) {
        // Do nothing
    }

    public void windowClosed(WindowEvent arg0) {
        // Do nothing
    }

    public void windowClosing(WindowEvent arg0) {
        
        // If we're not at the save point, launch the save tool
        if ( (ModelDocument.getInstance().size() > 0) && !CommandStack.getInstance().atSavePoint() ) {
            if ( JOptionPane.showConfirmDialog(null,
                    "File not saved. Do you wish to save?", "Save?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION ) {
                Tool saveTool = new SaveTool();
                saveTool.execute();
            }
        }
        
        // Write the application properties
        DGBGUI.getInstance().writeProperties();
    }

    public void windowDeactivated(WindowEvent arg0) {
        // Do nothing
    }

    public void windowDeiconified(WindowEvent arg0) {
        // Do nothing
    }

    public void windowIconified(WindowEvent arg0) {
        // Do nothing
    }

    public void windowOpened(WindowEvent arg0) {
        // Do nothing
    }
	
	
    private ModelDrivenOutlineView m_modelDrivenOutlineView;
    private DefaultCanvasView m_defaultCanvasView;
    private DefaultSelectionInspector m_selectionInspector;
    private ModelDrivenInspector m_modelDrivenInspector;
	private ErrorInspector m_errorInspector;
    private ModelDrivenResultsInspector m_modelDrivenResultsInspector;
    private JLabel m_statusBar;

    private Perspective m_perspective = Perspective.MODELDRIVEN;




	
}
